globals = {
	// Ακολουθεί η πόρτα στη οποία ο node server ακούει service requests.
	// Αυτή η πόρτα πρέπει να είναι γνωστή και στον server και στους clients.

	servicePort: 8888,

	// Ακολουθεί η πόρτα στη οποία ο node server ακούει monitor requests.
	// Αυτή η πόρτα πρέπει να είναι γνωστή και στον server και στους clients.

	monitorPort: 8889,

	// Ακολουθεί το default αρχείο εικόνας παρασκηνίου στο directory
	// "images/paraskinio".

	defaultParaskinio: 'standard.png',

	// Ακολουθεί η default κάσα για τα νέα τραπέζια.

	defaultKasa: 50,

	// Ακολουθεί ο default χρονικός παράγων του replay παρτίδας. Πρόκειται
	// για milliseconds ανά δευτερόλεπτο. Όσο μεγαλώνει, τόσο επιβραδύνεται
	// το replay.

	defaultMoviescale: 1000,
};

// Η function "walk" διατρέχει όλα τα στοιχεία μιας λίστας και για κάθε στοιχείο
// καλεί κάποια function με παραμέτρους το ανά χείρας κλειδί και το αντίστοιχο
// στοιχείο της λίστας. Η μέθοδος επιστρέφει το πλήθος των στοιχείων της λίστας.

globals.walk = function(list, callback) {
	var count = 0;
	for (var i in list) {
		count++;
		if (callback) callback(i, list[i]);
	}

	return count;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@
//
// Ακολουθούν functions σχετικές με ημερομηνία και ώρα.

// Η function "torams" επιστρέφει το τρέχον timestamp σε milliseconds,
// με όρους της μηχανής στην οποία εκτελείται.

globals.torams = function() {
	return (new Date).getTime();
}

// Η function "tora" επιστρέφει το τρέχον timestamp σε seconds,
// με όρους της μηχανής στην οποία εκτελείται.

globals.tora = function() {
	return Math.floor((new Date).getTime() / 1000);
}

// Η function "toramsServer" επιστρέφει το τρέχον timestamp
// σε milliseconds, με όρους του server.

globals.toramsServer = function() {
	return globals.torams() + (Client ? Client.timeDif * 1000 : 0);
}

// Η function "toraServer" επιστρέφει το τρέχον timestamp
// σε seconds, με όρους του server.

globals.toraServer = function() {
	return globals.tora() + (Client ? Client.timeDif : 0);
}

globals.pote = function(ts) {
	var tora = globals.tora();
	var dif = tora - ts;
	if (dif < 60) return 'τώρα';

	if (dif < 3600) {
		var x = parseInt(dif / 60);
		return 'πριν ' + x + ' λεπτ' + (x < 2 ? 'ό' : 'ά');
	}

	if (dif < 86400) {
		var x = parseInt(dif / 3600);
		return 'πριν ' + x + ' ώρ' + (x < 2 ? 'α' : 'ες');
	}
	
	ts = new Date(ts * 1000);
	return globals.mera(ts) + ', ' + globals.ora(ts);
}

// Η function "mera" δίνει την τρέχουσα ημερονηνία στη μηχανή που τρέχει.
// Μπορούμε να δώσουμε και συγκεκριμένη ώρα ως παράμετρο.

globals.mera = function(d) {
	if (d === undefined) d = new Date;
	var s = '';

	var x = d.getDate();
	if (x < 10) s += '0';
	s += x;
	s += '/';

	x = d.getMonth() + 1;
	if (x < 10) s += '0';
	s += x;
	s += '/'; 

	x = d.getFullYear();
	if (x < 2000) s += x;
	else {
		x %= 100;
		if (x < 10) s += '0';
		s += x;
	}

	return s;
}

// Η function "ora" δίνει την τρέχουσα ώρα στη μηχανή που τρέχει.
// Μπορούμε να δώσουμε και συγκεκριμένη ώρα ως παράμετρο.

globals.ora = function(d) {
	if (d === undefined) d = new Date;
	var s = '';

	var x = d.getHours();
	if (x < 10) s += '0';
	s += x + ':';

	x = d.getMinutes();
	if (x < 10) s += '0';
	s += x + ':';

	x = d.getSeconds();
	if (x < 10) s += '0';
	s += x;

	return s;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@
//
// Ακολουθούν βολικές μέθοδοι που αφορούν σε strings.

String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g, '');
}

String.prototype.ltrim = function() {
	return this.replace(/^\s+/, '');
}

String.prototype.rtrim = function() {
	return this.replace(/\s+$/, '');
}

String.prototype.isNai = function() {
	switch (this + '') {
	case 'ΝΑΙ': return 1;
	case 'ΟΧΙ': return 0;
	default: globals.fatal('String.isNai: ' + this + ': invalid value');
	}
}

// Η κλήση που ακολουθεί εξυπηρετεί στη λειτουργία άλλων μεθόδων.

;(function() {
	var ipOctet = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])';
	globals.ipRE = new RegExp('^(?:' + ipOctet + '\\.){3}' + ipOctet + '$');
	globals.emailRE = new RegExp('^[a-zA-Z0-9_\.-]+\@([a-zA-Z0-9-]+\.)+([a-zA-Z0-9]{2,4})+$');
	globals.loginRE = new RegExp('^[a-zA-Z][a-zA-Z0-9_!@#=.:+-]*$');
})();

// Η μέθοδος "validIp" ελέγχει ένα string ως προς το εαν είναι
// είναι δεκτό IP. Αν ναι το επιστρέφει, αλλιώς επιστρέφει κενό
// string.

String.prototype.validIp = function() {
	return this.match(globals.ipRE) ? this + '' : '';
}

// Η μέθοδος "validEmail" ελέγχει ένα string ως email address. Αν
// είναι δεκτό το επιστρέφει, αλλιώς επιστρέφει κενό string.

String.prototype.validEmail = function() {
	return this.match(globals.emailRE) ? this : '';
}

// Η μέθοδος "validLogin" ελέγχει ένα string ως login name. Αν
// είναι δεκτό το επιστρέφει, αλλιώς επιστρέφει κενό string.

String.prototype.validLogin = function() {
	return this.match(globals.loginRE) ? this : '';
}

// Η μέθοδος "uri το μετατρέπει ένα string σε μορφή ασφαλή
// ώστε να χρησιμοποιηθεί ως URI component.

String.prototype.uri = function() {
	return encodeURIComponent(this);
}

// Η μέθοδος "htmlSafe" μετατρέπει ένα string σε μορφή ασφαλή ώστε
// να μπορεί ενταχθεί παραθετικά σε HTML χωρίς να μεταφραστούν
// τα HTML tags που τυχόν περιέχει.

String.prototype.htmlSafe = function() {
	return this.replace(/&/g, '&amp;').replace(/</g, '&lt;');
}

// Η μέθοδος "scriptSafe" μετατρέπει ένα string σε μορφή ασφαλή ώστε
// να μπορεί ενταχθεί παραθετικά σε HTML χωρίς να μεταφραστούν
// τα script HTML tags που τυχόν περιέχει.

String.prototype.scriptSafe = function() {
	return this.replace(/script/ig, '&#8203;script');
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

// Η function "json" δέχεται μια παράμετρο και την μετατρέπει σε
// μορφή ασφαλή ώστε να χρησιμοποιηθεί ως rvalue σε δομές json.
// Η function δεν δίδεται ως string method ώστε να δύναται να
// χρησιμοποιηθεί σε οποιαδήποτε μεταβλητή και όχι μόνο σε strings.

globals.json = function(s) {
	var err = false;
	if (s === undefined) err = 'undefined data';
	else if (s === null) err = 'null data';
	else {
		switch (typeof s)  {
		case 'number':
			return s;
		case 'string':
			var x = s.replace(/\\/g, '\\\\');
			return "'" + x.replace(/'/g, '\\\'') + "'";
		default:
			err = s + ': invalid data type';
			break;
		}
	}

	globals.fatal('globals.json: ' + err);
}

// Η μέθοδος "random" επιστρέφει έναν τυχαίο ακέραιο μεταξύ των τιμών που δίνονται
// ως παράμετροι (inclusive). Π.χ. η κλήση globals.random(5, 10) μπορεί να δώσει 5,
// 6, 7, 8, 9 και 10.

globals.random = function(min, max) {
	switch (arguments.length) {
	case 0:
		min = 0;
		max = 999999999;
		break;
	case 1:
		max = min;
		min = 0;
		break;
	}

	return Math.floor(Math.random() * (max - min + 1)) + min;
}

// Η μέθοδος "randomString" επιστρέφει ένα τυχαίο string με μήκος που καθορίζεται
// από τις παραμέτρους. Το string αποτελείται από γράμματα του λατινικού αλφαβήτου,
// αλλά αν θέλουμε μπορούμε να περάσουμε αυθαίρετο string από το οποίο θα επιλεγούν
// χαρακτήρες.

globals.randomString = function(min, max, pool) {
	if (pool === undefined) pool = 'abcdefghijklmnopqrstuvwxyz';
	var ret = '';
	max = globals.random(min, max);
	for (min = 0; min < max; min++) ret += pool.substr(globals.random(pool.length - 1), 1);
	return ret;
}

if(!Array.isArray) Array.isArray = function (obj) {
	return Object.prototype.toString.call(obj) === "[object Array]";
}

globals.stringify = function(obj) {
	var x = '';
	var s = '{';
	for (var i in obj) {
		var tipos = typeof obj[i];
		switch (tipos) {
		case 'function':
			break;
		case 'object':
			if (Array.isArray(obj[i]))
				x += s + globals.stringifyProperty(i) + ':' + globals.stringifyArray(obj[i]);
			else
				x += s + globals.stringifyProperty(i) + ':' + globals.stringify(obj[i]);
			s = ',';
			break;
		case 'number':
			x += s + globals.stringifyProperty(i) + ':' + obj[i];
			s = ',';
			break;
		case 'string':
			x += s + globals.stringifyProperty(i) + ':' + globals.json(obj[i]);
			s = ',';
			break;
		default:
			globals.fatal('globals.stringify: ' + tipos + ': invalid data type');
		}
	}

	return s === ',' ? x + '}' : x + '{}';
}

globals.stringifyProperty = function(prop) {
	if (prop.match(/^[a-zA-Z_][a-zA-Z0-9_]*$/)) return prop;
	return globals.json(prop);
}

globals.stringifyArray = function(arr) {
	var s = '[', x = '', i;
	for (i = 0; i < arr.length; i++) {
		s += x + globals.stringify(arr[i]);
		x = ',';
	}
	return s + ']';
}

globals.fetchProp = function(obj, prop) {
	if (obj.hasOwnProperty(prop)) return obj[prop];
	globals.fatal(prop + ': missing property');
}

globals.fatal = function(msg) {
	try {
		Client.provlima(msg);
	} finally {
		throw new Error(msg);
	}
}
